/**
* @file video_processor.cpp
*
* Copyright (C) Huawei Technologies Co., Ltd. 2019-2020. All Rights Reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "video_processor.h"

#include <cstddef>
#include "securec.h"
#include "runtime/rt.h"
#include "utils/math_utils.h"
#include "error_codes_inner.h"
#include "aicpu/dvpp/dvpp_def.h"
#include "toolchain/profiling_manager.h"
#include "toolchain/resource_statistics.h"
#include "aicpu/common/aicpu_task_struct.h"
#include "single_op/dvpp/common/dvpp_util.h"

namespace {
    constexpr int32_t VDEC_CHANNEL_ID_CEILING = 31;
    constexpr uint64_t DVPP_EOS_CHANNEL_ABNORMAL = 16U;
    constexpr uint32_t VDEC_BIT_DEPTH_STRUCT_SIZE = static_cast<uint32_t>(sizeof(aicpu::dvpp::DvppVdecBitDepthConfig));
}

namespace acl {
    namespace dvpp {
    aclrtRunMode VideoProcessor::aclRunMode_(ACL_HOST);

    void VideoProcessor::SetVdecWaitTaskType(aclvdecChannelDesc *const channelDesc) const
    {
        channelDesc->vdecWaitTaskType = NOTIFY_TASK;
        ACL_LOG_INFO("vdec wait task type is notify");
    }

    aclError VideoProcessor::ResetVdecChannel(const aclvdecChannelDesc *const channelDesc) const
    {
        ACL_LOG_INFO("start to execute ResetVdecChannel, channelId = %u", channelDesc->vdecDesc.channelId);
        // reeset channel have 1 input
        constexpr uint32_t ioAddrNum = 1U;
        constexpr uint32_t argsSize = static_cast<uint32_t>(sizeof(aicpu::AicpuParamHead) +
            (ioAddrNum * sizeof(uint64_t)));
        const std::unique_ptr<char_t[]> args(new (std::nothrow)char_t[argsSize]);
        ACL_REQUIRES_NOT_NULL(args);
        const auto paramHead = reinterpret_cast<aicpu::AicpuParamHead *>(args.get());
        paramHead->length = argsSize;
        paramHead->ioAddrNum = ioAddrNum;
        const auto ioAddr = reinterpret_cast<uint64_t *>(args.get() + sizeof(aicpu::AicpuParamHead));
        ioAddr[0] = reinterpret_cast<uintptr_t>(channelDesc->dataBuffer.data);
        // launch reset vdec channel task
        rtArgsEx_t argsInfo = {};
        argsInfo.args = args.get();
        argsInfo.argsSize = argsSize;
        const rtError_t rtRet = rtCpuKernelLaunchWithFlag(acl::dvpp::DVPP_KERNELS_SONAME,
                                                          DVPP_RESET_VDEC_CHANNEL,
                                                          1U,
                                                          &argsInfo,
                                                          nullptr,
                                                          channelDesc->sendFrameStream,
                                                          RT_KERNEL_DEFAULT);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Task]vdec reset channel task call rtCpuKernelLaunchWithFlag failed, "
                "runtime errorCode = %d, channelId = %u.", rtRet, channelDesc->vdecDesc.channelId);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }

        ACL_LOG_INFO("Execute ResetVdecChannel success");
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::WaitEosIsTimeout(aclvdecChannelDesc *const channelDesc) const
    {
        if (!channelDesc->needResetChannelFlag.load()) {
            // send eos to send stream to finish decode all frame
            const aclError aclRet = SendEosForVdec(channelDesc);
            if ((aclRet != ACL_SUCCESS) && (!channelDesc->needResetChannelFlag.load())) {
                ACL_LOG_INNER_ERROR("[Send][Eos]send eos to sendFrameStream failed, errorCode = %d", aclRet);
                return aclRet;
            }
        }

        if (channelDesc->needResetChannelFlag.load()) {
            // in order to instruct aicpu to set channel to abnormal
            const aclError ret = ResetVdecChannel(channelDesc);
            if (ret != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Reset][Channel]reset channel failed, errorCode = %d, channelId = %u",
                    ret, channelDesc->vdecDesc.channelId);
                return ret;
            }

            (void)SendEosForVdec(channelDesc);
        }

        ACL_LOG_INFO("Execute WaitEosIsTimeout success, channelId = %u", channelDesc->vdecDesc.channelId);
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::VdecCreateChannel(aclvdecChannelDesc *const channelDesc, const bool isNeedNotify,
        const char_t *const kernelName)
    {
        const aclError aclRet = CreateNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
        if (aclRet != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Create][Notify]create notify and stream for vdec channel failed, "
                "result = %d", aclRet);
            return aclRet;
        }

        // subscribe report
        rtError_t rtRetVal = rtSubscribeReport(channelDesc->threadId, channelDesc->getFrameStream);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Subscribe][Report]subscribe report failed, errorCode = %d", rtRetVal);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }

        // memcpy data to device (both async and sync copy type are OK for this api)
        const size_t size = CalDevDvppStructRealUsedSize(&channelDesc->vdecDesc);
        if (aclRunMode_ == ACL_HOST) {
            rtRetVal = rtMemcpyAsync(channelDesc->dataBuffer.data, channelDesc->dataBuffer.length,
                static_cast<const void *>(&channelDesc->vdecDesc), size,
                RT_MEMCPY_HOST_TO_DEVICE, channelDesc->sendFrameStream);
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Copy][Mem]memcpy to device memory failed, size = %zu, "
                    "result = %d", size, rtRetVal);
                DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
                return ACL_GET_ERRCODE_RTS(rtRetVal);
            }
        }

        // create channel have only 2 input
        constexpr uint32_t addrNum = 2U;
        constexpr uint32_t argsSize = static_cast<uint32_t>(sizeof(aicpu::AicpuParamHead) +
            (addrNum * sizeof(uint64_t)));
        char_t args[argsSize] = {};
        const auto paramHead = reinterpret_cast<aicpu::AicpuParamHead *>(args);
        paramHead->length = argsSize;
        paramHead->ioAddrNum = addrNum;
        const auto ioAddr = reinterpret_cast<uint64_t *>(args + sizeof(aicpu::AicpuParamHead));
        ioAddr[0] = reinterpret_cast<uintptr_t>(channelDesc->dataBuffer.data);
        ioAddr[1] = reinterpret_cast<uintptr_t>(channelDesc->shareBuffer.data);

        // launch create channel task
        rtArgsEx_t argsInfo = {};
        argsInfo.args = args;
        argsInfo.argsSize = argsSize;
        rtRetVal = rtCpuKernelLaunchWithFlag(acl::dvpp::DVPP_KERNELS_SONAME,
                                             kernelName,
                                             1U,
                                             &argsInfo,
                                             nullptr,
                                             channelDesc->sendFrameStream,
                                             RT_KERNEL_DEFAULT);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Kernel]create vdec channel call rtCpuKernelLaunchWithFlag failed, "
                "runtime errorCode = %d", rtRetVal);
            (void) rtUnSubscribeReport(channelDesc->threadId, channelDesc->getFrameStream);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }

        // stream synchronize
        rtRetVal = rtStreamSynchronize(channelDesc->sendFrameStream);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Sync][Stream]fail to synchronize sendFrameStream, runtime errorCode = %d", rtRetVal);
            (void) rtUnSubscribeReport(channelDesc->threadId, channelDesc->getFrameStream);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }
        if (isNeedNotify) {
            ACL_LOG_INFO("success to call aclvdecCreateChannel, channelId=%u, sendFrameNotifyId=%u, "
                "getFrameNotifyId=%u, sendStreamId=%d, getStreamId=%d.",
                channelDesc->vdecDesc.channelId, channelDesc->vdecDesc.sendFrameNotifyId,
                channelDesc->vdecDesc.getFrameNotifyId, channelDesc->sendStreamId, channelDesc->getStreamId);
        } else {
            ACL_LOG_INFO("success to call aclvdecCreateChannel, channelId=%u, sendStreamId=%d, getStreamId=%d.",
                channelDesc->vdecDesc.channelId, channelDesc->sendStreamId, channelDesc->getStreamId);
        }

        channelDesc->isChannelAvailable = true;
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::aclvdecCreateChannel(aclvdecChannelDesc *const channelDesc)
    {
        ACL_LOG_INFO("start to execute aclvdecCreateChannel");
        ACL_REQUIRES_NOT_NULL(channelDesc->callback);
        ACL_REQUIRES_NOT_NULL(channelDesc->dataBuffer.data);
        const aclError aclRet = SetVdecParamToVdecChannel(channelDesc);
        if (aclRet != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Set][VdecParam]set vdec parameter failed, errorCode = %d", aclRet);
            return aclRet;
        }
        // record context of current thread
        const rtError_t getCtxRet = rtCtxGetCurrent(&channelDesc->vdecMainContext);
        if (getCtxRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][Ctx]get ctx failed, errorCode = %d", getCtxRet);
            return ACL_GET_ERRCODE_RTS(getCtxRet);
        }

        if (channelDesc->isNeedNotify) {
            SetVdecWaitTaskType(channelDesc);
            return VdecCreateChannel(channelDesc, true, DVPP_KERNELNAME_CREATE_VDEC_CHANNEL);
        } else {
            return VdecCreateChannel(channelDesc, false, DVPP_KERNELNAME_CREATE_VDEC_CHANNEL_V2);
        }
    }

    aclError VideoProcessor::VdecDestroyChannel(aclvdecChannelDesc *const channelDesc, const bool isNeedNotify,
        const char_t *const kernelName) const
    {
        const aclError ret = WaitEosIsTimeout(channelDesc);
        if (ret != ACL_SUCCESS) {
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            ACL_LOG_INNER_ERROR("[Check][Timeout]execute WaitEosIsTimeout failed, errorCode = %d, channelId = %u",
                ret, channelDesc->vdecDesc.channelId);
            return ret;
        }

        // wait finish all callback task
        rtError_t rtRetVal = rtStreamSynchronize(channelDesc->getFrameStream);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Sync][Stream]fail to synchronize getFrameStream, runtime errorCode = %d.", rtRetVal);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }

        // destroy channel have 1 input
        constexpr uint32_t ioAddrNum = 1U;
        constexpr uint32_t argsSize = static_cast<uint32_t>(sizeof(aicpu::AicpuParamHead) +
            (ioAddrNum * sizeof(uint64_t)));
        char_t args[argsSize] = {};
        const auto cpuParamHead = reinterpret_cast<aicpu::AicpuParamHead *>(args);
        cpuParamHead->length = argsSize;
        cpuParamHead->ioAddrNum = ioAddrNum;

        const auto ioAddr = reinterpret_cast<uint64_t *>(args + sizeof(aicpu::AicpuParamHead));
        ioAddr[0] = reinterpret_cast<uintptr_t>(channelDesc->dataBuffer.data);

        rtArgsEx_t argsInfo = {};
        argsInfo.args = args;
        argsInfo.argsSize = argsSize;
        rtRetVal = rtCpuKernelLaunchWithFlag(acl::dvpp::DVPP_KERNELS_SONAME, kernelName, 1U, &argsInfo, nullptr,
            channelDesc->sendFrameStream, RT_KERNEL_DEFAULT);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Kernel]vdec destory channel call rtCpuKernelLaunchWithFlag failed, "
                "runtime errorCode = %d.", rtRetVal);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }

        rtRetVal = rtStreamSynchronize(channelDesc->sendFrameStream);
        if (rtRetVal != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Sync][Stream]fail to synchronize sendFrameStream, runtime errorCode = %d", rtRetVal);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRetVal);
        }

        (void)rtUnSubscribeReport(channelDesc->threadId, channelDesc->getFrameStream);
        // destory all notify and stream
        DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);

        channelDesc->isChannelAvailable = false;
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::aclvdecDestroyChannel(aclvdecChannelDesc *const channelDesc)
    {
        ACL_REQUIRES_NOT_NULL(channelDesc);
        ACL_REQUIRES_NOT_NULL(channelDesc->dataBuffer.data);
        ACL_LOG_INFO("start to execute aclvdecDestroyChannel, channelId = %u", channelDesc->vdecDesc.channelId);

        if (channelDesc->isNeedNotify) {
            return VdecDestroyChannel(channelDesc, true, DVPP_KERNELNAME_DESTROY_VDEC_CHANNEL);
        } else {
            return VdecDestroyChannel(channelDesc, false, DVPP_KERNELNAME_DESTROY_VDEC_CHANNEL_V2);
        }
    }

    aclError VideoProcessor::CheckAndCopyVdecInfoData(const acldvppStreamDesc *const input,
        const acldvppPicDesc *const output, const bool isSkipFlag) const
    {
        ACL_REQUIRES_NOT_NULL(input);
        ACL_REQUIRES_NOT_NULL(input->dataBuffer.data);

        // eos frame does not support skipping
        if (input->dvppStreamDesc.eos && isSkipFlag) {
            ACL_LOG_INNER_ERROR("[Check][Params]eos frame does not support skipping");
            return ACL_ERROR_FEATURE_UNSUPPORTED;
        }

        // no skipped data frame will be decoded
        if ((!input->dvppStreamDesc.eos) && (!isSkipFlag)) {
            ACL_REQUIRES_NOT_NULL(output);
            ACL_REQUIRES_NOT_NULL(output->dataBuffer.data);
            // copy outputPicDesc to device
            if (aclRunMode_ == ACL_HOST) {
                constexpr size_t size = sizeof(aicpu::dvpp::DvppPicDesc);
                const rtError_t memcpyOutputRet = rtMemcpy(output->dataBuffer.data, output->dataBuffer.length,
                                                           static_cast<const void *>(&output->dvppPicDesc), size,
                                                           RT_MEMCPY_HOST_TO_DEVICE);
                if (memcpyOutputRet != RT_ERROR_NONE) {
                    ACL_LOG_CALL_ERROR("[Copy][Mem]memcpy output pic desc to device memory failed, size = %zu,"
                        " runtime errorCode = %d.", size, memcpyOutputRet);
                    return ACL_GET_ERRCODE_RTS(memcpyOutputRet);
                }
            }
        }

        // copy inputStreamDesc to device
        ACL_LOG_INFO("begin to send frame. frame size is %u.", input->dvppStreamDesc.size);
        if (aclRunMode_ == ACL_HOST) {
            constexpr size_t size = sizeof(aicpu::dvpp::DvppStreamDesc);
            const rtError_t memcpyInputRet = rtMemcpy(input->dataBuffer.data, input->dataBuffer.length,
                                                      static_cast<const void *>(&input->dvppStreamDesc), size,
                                                      RT_MEMCPY_HOST_TO_DEVICE);
            if (memcpyInputRet != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Copy][Mem]memcpy input stream desc to device memory failed, "
                    "size = %zu, runtime errorCode = %d.", size, memcpyInputRet);
                return ACL_GET_ERRCODE_RTS(memcpyInputRet);
            }
        }
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::aclvdecSendFrame(aclvdecChannelDesc *const channelDesc,
                                              acldvppStreamDesc *input,
                                              acldvppPicDesc *output,
                                              aclvdecFrameConfig *const config,
                                              void *userData,
                                              const bool isSkipFlag) const
    {
        (void)(config);
        ACL_REQUIRES_NOT_NULL(channelDesc);
        if (!channelDesc->isChannelAvailable) {
            ACL_LOG_ERROR("please execute aclvdecCreateChannel before aclvdecSendFrame");
            return ACL_ERROR_INVALID_PARAM;
        }
        ACL_REQUIRES_NOT_NULL(channelDesc->callback);
        ACL_REQUIRES_NOT_NULL(channelDesc->dataBuffer.data);
        ACL_REQUIRES_NOT_NULL(channelDesc->sendFrameStream);
        ACL_REQUIRES_NOT_NULL(channelDesc->getFrameStream);

        ACL_LOG_INFO("start to execute aclvdecSendFrame, channelId=%u, isSkipFlag=%d.",
            channelDesc->vdecDesc.channelId, static_cast<int32_t>(isSkipFlag));
        const aclError memcpyRet = CheckAndCopyVdecInfoData(input, output, isSkipFlag);
        if (memcpyRet != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Check][Stream]check and copy stream desc or pic desc failed, "
                "result = %d.", memcpyRet);
            return memcpyRet;
        }

        bool eos = input->dvppStreamDesc.eos;
        uint64_t frameId = 0U;
        if (!eos) {
            ++channelDesc->frameId;
            frameId = channelDesc->frameId;
            ACL_LOG_DEBUG("vdec process data frame: channelId = %u, frameId = %lu.",
                channelDesc->vdecDesc.channelId, frameId);
        }

        aicpu::dvpp::VdecCallbackInfoPtr callbackInfoPtr = nullptr;
        try {
            callbackInfoPtr = std::make_shared<aicpu::dvpp::VdecGetFrameCallbackInfo>(
                input, output, userData, eos);
        } catch (std::bad_alloc &) {
            ACL_LOG_INNER_ERROR("[Make][Shared]Make shared for get frame callback info failed.");
            return ACL_ERROR_BAD_ALLOC;
        }
        // must insert callbackMap before sendframe, otherwise callbackMap may find no frameid in callback thread
        {
            const std::unique_lock<std::mutex> locker{channelDesc->mutexForCallbackMap};
            channelDesc->callbackMap[frameId] = callbackInfoPtr;
        }

        aclError launchRet = LaunchTaskForSendStream(channelDesc, input, output, eos);
        if (launchRet != ACL_SUCCESS) {
            {
                const std::unique_lock<std::mutex> locker{channelDesc->mutexForCallbackMap};
                (void)channelDesc->callbackMap.erase(frameId);
            }
            ACL_LOG_INNER_ERROR("[Launch][Task]launch tasks for send stream failed, errorCode = %d.", launchRet);
            return launchRet;
        }

        // only launch task for get stream when frame counter != 0
        bool needLaunchTaskForGetStream = false;
        {
            const std::lock_guard<std::mutex> queueLock(channelDesc->mutexForQueue);
            if (channelDesc->queueEmptyFlag.load()) {
                needLaunchTaskForGetStream = true;
                channelDesc->queueEmptyFlag.store(false);
            } else {
                // save get frame task info to queue of current channel
                channelDesc->taskQueue.push(callbackInfoPtr);
                ACL_LOG_INFO("channelId=%u, task queue size is %zu.",
                    channelDesc->vdecDesc.channelId, channelDesc->taskQueue.size());
            }
        }

        if (needLaunchTaskForGetStream) {
            ACL_LOG_INFO("launch tasks in get stream only for first frame, channelId=%u.",
                channelDesc->vdecDesc.channelId);
            launchRet = LaunchTaskForGetStream(channelDesc);
            if (launchRet != ACL_SUCCESS) {
                {
                    const std::unique_lock<std::mutex> locker{channelDesc->mutexForCallbackMap};
                    (void)channelDesc->callbackMap.erase(frameId);
                }
                ACL_LOG_INNER_ERROR("[Launch][Tasks]launch tasks for get stream failed, errorCode = %d.", launchRet);
                return launchRet;
            }
        }

        // streamSynchronize send frame stream
        const rtError_t streamSynRet = rtStreamSynchronize(channelDesc->sendFrameStream);
        if (streamSynRet != RT_ERROR_NONE) {
            {
                const std::unique_lock<std::mutex> locker {channelDesc->mutexForCallbackMap};
                (void)channelDesc->callbackMap.erase(frameId);
            }
            ACL_LOG_CALL_ERROR("[Sync][Stream]fail to synchronize sendFrameStream, runtime errorCode = %d.",
                streamSynRet);
            return ACL_GET_ERRCODE_RTS(streamSynRet);
        }

        if (eos) {
            ACL_LOG_INFO("begin to synchronize get stream for eos, channelId = %u.", channelDesc->vdecDesc.channelId);
            std::unique_lock<std::mutex> locker{channelDesc->mutexForQueue};
            // check eos back flag
            while (!channelDesc->eosBackFlag.load()) {
                ACL_LOG_INFO("eos wait, channelId=%u.", channelDesc->vdecDesc.channelId);
                channelDesc->condVarForEos.wait(locker);
            }
            ACL_LOG_INFO("finish to synchronize get stream for eos, channelId = %u.", channelDesc->vdecDesc.channelId);
            // must clear cached tasks, especially for eos, reset eosBackFlag and queueEmptyFlag
            ClearCachedTasks(channelDesc);
            return ACL_SUCCESS;
        }

        if (channelDesc->isNeedNotify) {
            ACL_LOG_INFO("end to send frame. channelId=%u, frameId is %lu, sendFrameNotifyId=%u, getFrameNotifyId=%u, "
                "sendStreamId=%d, getStreamId=%d.", channelDesc->vdecDesc.channelId, frameId,
                channelDesc->vdecDesc.sendFrameNotifyId, channelDesc->vdecDesc.getFrameNotifyId,
                channelDesc->sendStreamId, channelDesc->getStreamId);
        } else {
            ACL_LOG_INFO("end to send frame. channelId=%u, frameId is %lu, sendStreamId=%d, getStreamId=%d.",
                channelDesc->vdecDesc.channelId, frameId, channelDesc->sendStreamId, channelDesc->getStreamId);
        }
        return ACL_SUCCESS;
    }

    aclvdecChannelDesc *VideoProcessor::aclvdecCreateChannelDesc() const
    {
        aclvdecChannelDesc *aclChannelDesc = nullptr;
        switch (aclRunMode_) {
            case ACL_HOST: {
                aclChannelDesc = CreateVdecChannelDescOnHost();
                break;
            }
            case ACL_DEVICE: {
                aclChannelDesc = CreateVdecChannelDescOnDevice();
                break;
            }
            default: {
                ACL_LOG_INNER_ERROR("[Unknown][Mode]unkown acl run mode %d.", aclRunMode_);
                return nullptr;
            }
        }
        return aclChannelDesc;
    }

    aclError VideoProcessor::aclvdecDestroyChannelDesc(aclvdecChannelDesc *channelDesc) const
    {
        if (channelDesc == nullptr) {
            return ACL_SUCCESS;
        }

        if (channelDesc->isChannelAvailable) {
            ACL_LOG_ERROR("Vdec channel should be destroyed first before running aclvdecDestroyChannelDesc");
            return ACL_ERROR_RELATIVE_RESOURCE_NOT_CLEARED;
        }

        {
            const std::unique_lock<std::mutex> locker{channelDesc->mutexForTLVMap};
            channelDesc->tlvParamMap.clear();
        }

        switch (aclRunMode_) {
            case ACL_DEVICE: {
                channelDesc->~aclvdecChannelDesc();
                FreeDeviceAddr(static_cast<void *>(channelDesc));
                break;
            }
            case ACL_HOST: {
                channelDesc->~aclvdecChannelDesc();
                FreeDeviceBuffer(channelDesc->dataBuffer);
                ACL_ALIGN_FREE(channelDesc);
                break;
            }
            default: {
                ACL_LOG_INNER_ERROR("[Check][RunMode]vdec destroy channel desc, unkown acl run mode %d.", aclRunMode_);
                return ACL_ERROR_INTERNAL_ERROR;
            }
        }
        return ACL_SUCCESS;
    }

    acldvppStreamDesc *VideoProcessor::acldvppCreateStreamDesc() const
    {
        acldvppStreamDesc *aclStreamDesc = nullptr;
        switch (aclRunMode_) {
            case ACL_HOST: {
                aclStreamDesc = CreateDvppStreamDescOnHost();
                break;
            }
            case ACL_DEVICE: {
                aclStreamDesc = CreateDvppStreamDescOnDevice();
                break;
            }
            default: {
                ACL_LOG_INNER_ERROR("[Check][RunMode]unkown acl run mode %d.", aclRunMode_);
                return nullptr;
            }
        }
        return aclStreamDesc;
    }

    aclError VideoProcessor::acldvppDestroyStreamDesc(acldvppStreamDesc *streamDesc)
    {
        ACL_LOG_INFO("start to execute acldvppDestroyStreamDesc");
        if (streamDesc == nullptr) {
            ACL_LOG_WARN("streamDesc is null.");
            return ACL_SUCCESS;
        }

        switch (aclRunMode_) {
            case ACL_HOST: {
                FreeDeviceBuffer(streamDesc->dataBuffer);
                ACL_ALIGN_FREE(streamDesc);
                break;
            }
            case ACL_DEVICE: {
                FreeDeviceAddr(static_cast<void *>(streamDesc));
                break;
            }
            default: {
                ACL_LOG_INNER_ERROR("[Check][RunMode]unkown acl run mode %d.", aclRunMode_);
                return ACL_ERROR_INTERNAL_ERROR;
            }
        }
        ACL_LOG_INFO("successfully execute acldvppDestroyStreamDesc");
        return ACL_SUCCESS;
    }

    aclvdecFrameConfig *VideoProcessor::aclvdecCreateFrameConfig() const
    {
        ACL_LOG_INFO("start to execute aclvdecCreateFrameConfig");
        aclvdecFrameConfig *aclVdecFrameConfigPtr = nullptr;
        // malloc memory
        const size_t aclVdecFrameConfigSize = CalAclDvppStructSize(aclVdecFrameConfigPtr);
        ACL_REQUIRES_POSITIVE_RET_NULL(aclVdecFrameConfigSize);
        void *addr = malloc(aclVdecFrameConfigSize);
        if (addr == nullptr) {
            ACL_LOG_INNER_ERROR("[Malloc][Mem]malloc memory failed. size is %zu.", aclVdecFrameConfigSize);
            return nullptr;
        }

        // create aclvdecFrameConfig in memory
        aclVdecFrameConfigPtr = new (addr)aclvdecFrameConfig();
        if (aclVdecFrameConfigPtr == nullptr) {
            ACL_LOG_INNER_ERROR("[Check][FrameConfig]new aclvdecFrameConfig failed");
            ACL_FREE(addr);
            return nullptr;
        }
        return aclVdecFrameConfigPtr;
    }

    aclError VideoProcessor::aclvdecDestroyFrameConfig(aclvdecFrameConfig *vdecFrameConfig) const
    {
        ACL_FREE(vdecFrameConfig);
        return ACL_SUCCESS;
    }

    /**
     * memcpy data to device.
     * @param output output dvpp stream desc
     * @return ACL_SUCCESS for success, other for failed
     */
    aclError VideoProcessor::MemcpyDataToDevice(const acldvppStreamDesc *const output) const
    {
        constexpr size_t size = sizeof(aicpu::dvpp::DvppStreamDesc);
        const rtError_t rtRet = rtMemcpy(output->dataBuffer.data, output->dataBuffer.length,
            static_cast<const void *>(&output->dvppStreamDesc), size,
            RT_MEMCPY_HOST_TO_DEVICE);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Copy][Mem]memcpy to device memory failed, size = %zu, "
                "runtime errorCode = %d", size, rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::SetVdecParamToVdecChannel(aclvdecChannelDesc *const channelDesc) const
    {
        uint32_t offset = VDEC_BIT_DEPTH_STRUCT_SIZE;
        const std::unique_lock<std::mutex> locker{channelDesc->mutexForTLVMap};
        for (auto &it : channelDesc->tlvParamMap) {
            if (it.first != VDEC_BIT_DEPTH) { // for compatibility, bit depth should be special treated
                ACL_REQUIRES_NOT_NULL(it.second.value.get());
                uint32_t tmpOffset = offset;
                ACL_CHECK_ASSIGN_UINT32T_ADD(tmpOffset, static_cast<uint32_t>(it.second.valueLen), tmpOffset);
                if (tmpOffset > VDEC_CHANNEL_DESC_TLV_LEN) {
                    ACL_LOG_INNER_ERROR("[Check][Offset] offset %u can not be larger than %u",
                                        tmpOffset, VDEC_CHANNEL_DESC_TLV_LEN);
                    return ACL_ERROR_FAILURE;
                }
                const auto ret = memcpy_s(channelDesc->vdecDesc.extendInfo + offset, it.second.valueLen,
                                          it.second.value.get(), it.second.valueLen);
                if (ret != EOK) {
                    ACL_LOG_INNER_ERROR("[Copy][Mem]call memcpy_s failed, result = %d, srcLen = %zu, dstLen = %zu",
                                        ret, it.second.valueLen, it.second.valueLen);
                    return ACL_ERROR_FAILURE;
                }
                offset += static_cast<uint32_t>(it.second.valueLen);
            }
        }
        channelDesc->vdecDesc.len = offset;
        // for compatibility, bit depth must be in front of extendInfo
        std::map<acl::VdecTLVType, acl::VdecChannelDescTLVParam>::const_iterator itBitDepth =
                channelDesc->tlvParamMap.find(VDEC_BIT_DEPTH);
        if (itBitDepth != channelDesc->tlvParamMap.cend()) {
            const auto ret = memcpy_s(channelDesc->vdecDesc.extendInfo, VDEC_BIT_DEPTH_STRUCT_SIZE,
                                      itBitDepth->second.value.get(), itBitDepth->second.valueLen);
            if (ret != EOK) {
                ACL_LOG_INNER_ERROR("[Copy][Mem]call memcpy_s failed, result = %d, srcLen = %zu, dstLen = %u", ret,
                                    itBitDepth->second.valueLen, VDEC_BIT_DEPTH_STRUCT_SIZE);
                return ACL_ERROR_FAILURE;
            }
        } else if (offset > VDEC_BIT_DEPTH_STRUCT_SIZE) {
            constexpr aicpu::dvpp::DvppVdecBitDepthConfig tmpDvppVdecBitDepthConfig;
            const auto ret = memcpy_s(channelDesc->vdecDesc.extendInfo, VDEC_BIT_DEPTH_STRUCT_SIZE,
                                      &tmpDvppVdecBitDepthConfig, VDEC_BIT_DEPTH_STRUCT_SIZE);
            if (ret != EOK) {
                ACL_LOG_INNER_ERROR("[Copy][Mem]call memcpy_s failed, result = %d, srcLen = %u, dstLen = %u", ret,
                                    VDEC_BIT_DEPTH_STRUCT_SIZE, VDEC_BIT_DEPTH_STRUCT_SIZE);
                return ACL_ERROR_FAILURE;
            }
        } else {
            channelDesc->vdecDesc.len = 0U;
        }
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::aclvdecSetChannelDescMatrix(aclvdecChannelDesc *const channelDesc,
        const acldvppCscMatrix matrixFormat) const
    {
        (void)(channelDesc);
        (void)(matrixFormat);
        ACL_LOG_ERROR("[Unsupport][Feature]Setting descMatrix for channel desc is not "
            "supported in this version. Please check.");
        const char_t *argList[] = {"feature", "reason"};
        const char_t *argVal[] = {"Setting descMatrix for channel desc", "please check"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::UNSUPPORTED_FEATURE_MSG,
            argList, argVal, 2U);
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    aclError VideoProcessor::aclvdecGetChannelDescMatrix(const aclvdecChannelDesc *const channelDesc,
        acldvppCscMatrix &matrixFormat) const
    {
        (void)(channelDesc);
        (void)(matrixFormat);
        ACL_LOG_ERROR("[Unsupport][Feature]Getting descMatrix for channel desc is not "
            "supported in this version. Please check.");
        const char_t *argList[] = {"feature", "reason"};
        const char_t *argVal[] = {"Getting descMatrix for channel desc", "please check"};
        acl::AclErrorLogManager::ReportInputErrorWithChar(acl::UNSUPPORTED_FEATURE_MSG,
            argList, argVal, 2U);
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    acldvppStreamDesc *VideoProcessor::CreateDvppStreamDescOnHost() const
    {
        acldvppStreamDesc *aclStreamDesc = nullptr;
        // alloc host memory
        const size_t aclStreamDescSize = CalAclDvppStructSize(aclStreamDesc);
        ACL_REQUIRES_POSITIVE_RET_NULL(aclStreamDescSize);
        const size_t pageSize = mmGetPageSize();
        void *hostAddr = mmAlignMalloc(aclStreamDescSize, pageSize);
        if (hostAddr == nullptr) {
            ACL_LOG_INNER_ERROR("[Malloc][Mem]malloc memory failed. size is %zu.", aclStreamDescSize);
            return nullptr;
        }

        // create acldvppStreamDesc in host memory
        aclStreamDesc = new (hostAddr)acldvppStreamDesc;
        RETURN_NULL_WITH_ALIGN_FREE(aclStreamDesc, hostAddr);

        // malloc device memory for vdecChannelDesc
        void *devPtr = nullptr;
        const size_t dataSize = CalAclDvppStructSize(&aclStreamDesc->dvppStreamDesc);
        constexpr uint32_t flags = RT_MEMORY_DEFAULT | RT_MEMORY_POLICY_DEFAULT_PAGE_ONLY;
        const rtError_t ret = rtMalloc(&devPtr, dataSize, flags, acl::ACL_MODE_ID_U16);
        if (ret != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Malloc][Mem]malloc device memory for acl dvpp stream desc failed, "
                "runtime errorCode = %d", ret);
            ACL_ALIGN_FREE(hostAddr);
            return nullptr;
        }

        // set data buffer
        aclStreamDesc->dataBuffer.data = devPtr;
        aclStreamDesc->dataBuffer.length = dataSize;

        return aclStreamDesc;
    }

    acldvppStreamDesc *VideoProcessor::CreateDvppStreamDescOnDevice() const
    {
        acldvppStreamDesc *aclStreamDesc = nullptr;
        // alloc device memory
        void *devAddr = nullptr;
        const size_t aclStreamDescSize = CalAclDvppStructSize(aclStreamDesc);
        constexpr uint32_t flags = RT_MEMORY_DEFAULT | RT_MEMORY_POLICY_DEFAULT_PAGE_ONLY;
        const rtError_t rtErr = rtMalloc(&devAddr, static_cast<uint64_t>(aclStreamDescSize), flags,
            acl::ACL_MODE_ID_U16);
        if (rtErr != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Malloc][Mem]alloc device memory failed, size = %zu, "
                "runtime errorCode = %d", aclStreamDescSize, rtErr);
            return nullptr;
        }

        // create acldvppStreamDesc in device addr
        aclStreamDesc = new (devAddr)acldvppStreamDesc;
        if (aclStreamDesc == nullptr) {
            ACL_LOG_INNER_ERROR("[Malloc][StreamDesc]new acldvppStreamDesc failed");
            (void) rtFree(devAddr);
            devAddr = nullptr;
            return nullptr;
        }

        // set data buffer
        const size_t offset = OFFSET_OF_MEMBER(acldvppStreamDesc, dvppStreamDesc);
        aclStreamDesc->dataBuffer.data = reinterpret_cast<aicpu::dvpp::DvppVdecDesc *>(
            reinterpret_cast<uintptr_t>(devAddr) + offset);
        aclStreamDesc->dataBuffer.length = CalAclDvppStructSize(&aclStreamDesc->dvppStreamDesc);

        return aclStreamDesc;
    }

    aclvdecChannelDesc *VideoProcessor::CreateVdecChannelDescOnHost() const
    {
        aclvdecChannelDesc *aclChannelDesc = nullptr;
        // alloc host memory
        const size_t aclChannelDescSize = CalAclDvppStructSize(aclChannelDesc);
        ACL_REQUIRES_POSITIVE_RET_NULL(aclChannelDescSize);
        const size_t pageSize = mmGetPageSize();
        void *hostAddr = mmAlignMalloc(aclChannelDescSize, pageSize);
        if (hostAddr == nullptr) {
            ACL_LOG_INNER_ERROR("[Malloc][Mem]malloc memory failed. size is %zu.", aclChannelDescSize);
            return nullptr;
        }

        // create aclvdecChannelDesc in host addr
        aclChannelDesc = new (hostAddr)aclvdecChannelDesc;
        if ((aclChannelDesc == nullptr) || (aclChannelDesc->vdecDesc.extendInfo == nullptr)) {
            ACL_LOG_INNER_ERROR("[Create][VdecChannelDesc]create aclvdecChannelDesc with function new failed");
            ACL_ALIGN_FREE(hostAddr);
            return nullptr;
        }
        const auto err = memset_s(aclChannelDesc->vdecDesc.extendInfo, acl::dvpp::VDEC_CHANNEL_DESC_TLV_LEN,
            0, acl::dvpp::VDEC_CHANNEL_DESC_TLV_LEN);
        if (err != EOK) {
            ACL_LOG_INNER_ERROR("[Set][Mem]set vdecDesc extendInfo to 0 failed, dstLen = %u, srclen = %u, "
                "result = %d.", aclChannelDesc->vdecDesc.len, aclChannelDesc->vdecDesc.len, err);
            aclChannelDesc->~aclvdecChannelDesc();
            ACL_ALIGN_FREE(hostAddr);
            return nullptr;
        }
        // malloc device memory for vdecChannelDesc
        void *devPtr = nullptr;
        const size_t dataSize = CalAclDvppStructSize(&aclChannelDesc->vdecDesc);
        const size_t totalSize = dataSize + acl::dvpp::VDEC_CHANNEL_SHARE_BUFFER_SIZE;
        constexpr uint32_t flags = RT_MEMORY_DEFAULT | RT_MEMORY_POLICY_DEFAULT_PAGE_ONLY;
        const rtError_t ret = rtMalloc(&devPtr, totalSize, flags, acl::ACL_MODE_ID_U16);
        if (ret != RT_ERROR_NONE) {
            ACL_LOG_INNER_ERROR("[Malloc][Mem]malloc device memory for acl vdec channel desc failed, "
                "runtime errorCode = %d", ret);
            aclChannelDesc->~aclvdecChannelDesc();
            ACL_ALIGN_FREE(hostAddr);
            return nullptr;
        }

        // set data buffer
        aclChannelDesc->dataBuffer.data = devPtr;
        aclChannelDesc->dataBuffer.length = dataSize;

        aclChannelDesc->shareBuffer.data = static_cast<char_t *>(devPtr) + dataSize;
        aclChannelDesc->shareBuffer.length = acl::dvpp::VDEC_CHANNEL_SHARE_BUFFER_SIZE;

        return aclChannelDesc;
    }

    aclvdecChannelDesc *VideoProcessor::CreateVdecChannelDescOnDevice() const
    {
        aclvdecChannelDesc *aclChannelDesc = nullptr;
        // alloc device memory
        void *devAddr = nullptr;
        const size_t aclChannelDescSize = CalAclDvppStructSize(aclChannelDesc);
        constexpr uint32_t flags = RT_MEMORY_DEFAULT | RT_MEMORY_POLICY_DEFAULT_PAGE_ONLY;
        const rtError_t rtErr = rtMalloc(&devAddr, static_cast<uint64_t>(aclChannelDescSize), flags,
            acl::ACL_MODE_ID_U16);
        if (rtErr != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Malloc][Mem]alloc device memory failed, size = %zu, runtime errorCode = %d",
                aclChannelDescSize, rtErr);
            return nullptr;
        }

        // create aclvdecChannelDesc in device addr
        aclChannelDesc = new (devAddr)aclvdecChannelDesc;
        if ((aclChannelDesc == nullptr) || (aclChannelDesc->vdecDesc.extendInfo == nullptr)) {
            ACL_LOG_INNER_ERROR("[Create][ChannelDesc]create aclvdecChannelDesc with function new failed");
            (void) rtFree(devAddr);
            devAddr = nullptr;
            return nullptr;
        }
        const auto err = memset_s(aclChannelDesc->vdecDesc.extendInfo, acl::dvpp::VDEC_CHANNEL_DESC_TLV_LEN,
            0, acl::dvpp::VDEC_CHANNEL_DESC_TLV_LEN);
        if (err != EOK) {
            ACL_LOG_INNER_ERROR("[Set][Mem]set vdecDesc extendInfo to 0 failed, dstLen = %u, srclen = %u, "
                "result = %d.", aclChannelDesc->vdecDesc.len, aclChannelDesc->vdecDesc.len, err);
            aclChannelDesc->~aclvdecChannelDesc();
            (void) rtFree(devAddr);
            devAddr = nullptr;
            return nullptr;
        }

        // set data buffer
        size_t offset = OFFSET_OF_MEMBER(aclvdecChannelDesc, vdecDesc);
        aclChannelDesc->dataBuffer.data = reinterpret_cast<aicpu::dvpp::DvppVdecDesc *>(
            reinterpret_cast<uintptr_t>(devAddr) + offset);
        aclChannelDesc->dataBuffer.length = CalAclDvppStructSize(&aclChannelDesc->vdecDesc);

        // malloc device addr for share buffer
        offset = OFFSET_OF_MEMBER(aclvdecChannelDesc, callbackResult);
        aclChannelDesc->shareBuffer.data = reinterpret_cast<VdecCallbackResultInfo *>(
            reinterpret_cast<uintptr_t>(devAddr) + offset);
        aclChannelDesc->shareBuffer.length = acl::dvpp::VDEC_CHANNEL_SHARE_BUFFER_SIZE;

        return aclChannelDesc;
    }

    aclError VideoProcessor::SendEosForVdec(aclvdecChannelDesc *const channelDesc) const
    {
        // create input stream desc
        acldvppStreamDesc *const eosStreamDesc = acldvppCreateStreamDesc();
        if (eosStreamDesc == nullptr) {
            ACL_LOG_INNER_ERROR("[Create][Stream]fail to create dvpp stream desc for eos.");
            return ACL_ERROR_FAILURE;
        }

        // set eos for eos stream desc
        aclError ret = acldvppSetStreamDescEos(eosStreamDesc, true);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Set][Stream]fail to set eos for stream desc, errorCode = %d", ret);
            (void) acldvppDestroyStreamDesc(eosStreamDesc);
            return ret;
        }

        // send eos and synchronize
        ret = aclvdecSendFrame(channelDesc, eosStreamDesc, nullptr, nullptr, nullptr, false);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Send][Frame]fail to send eos, errorCode = %d", ret);
            (void) acldvppDestroyStreamDesc(eosStreamDesc);
            return ret;
        }

        // destroy input stream desc
        ret = acldvppDestroyStreamDesc(eosStreamDesc);
        if (ret != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Destroy][StreamDesc]fail to destory dvpp stream desc for eos, errorCode = %d", ret);
            return ret;
        }
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::GetVdecCallInfo(aclvdecChannelDesc *const channelDesc, acldvppStreamDesc *&input,
        acldvppPicDesc *&output, void *&userData, bool &eos)
    {
        const rtError_t ret = rtMemcpy(static_cast<void *>(&(channelDesc->callbackResult)),
            sizeof(VdecCallbackResultInfo), channelDesc->shareBuffer.data,
            sizeof(VdecCallbackResultInfo), RT_MEMCPY_DEVICE_TO_HOST);
        if (ret != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Copy][Mem]memcpy frameId to host memory failed, dstSize = %zu, srcSize = %zu, "
                "runtime errorCode = %d", sizeof(VdecCallbackResultInfo), sizeof(VdecCallbackResultInfo), ret);
            return ACL_GET_ERRCODE_RTS(ret);
        }
        const uint64_t frameId = channelDesc->callbackResult.frameId;
        aicpu::dvpp::VdecCallbackInfoPtr callbackInfoPtr = nullptr;
        {
            const std::unique_lock<std::mutex> locker{channelDesc->mutexForCallbackMap};
            if (channelDesc->callbackMap.find(frameId) == channelDesc->callbackMap.end()) {
                ACL_LOG_INNER_ERROR("[Find][FrameId]the value of frameId[%lu] is invalid, channelId = %u",
                    frameId, channelDesc->vdecDesc.channelId);
                return ACL_ERROR_INTERNAL_ERROR;
            }
            callbackInfoPtr = channelDesc->callbackMap[frameId];
            (void)channelDesc->callbackMap.erase(frameId);
        }
        if (callbackInfoPtr == nullptr) {
            ACL_LOG_INNER_ERROR("[Check][CallbackInfoPtr]callbackInfoPtr is nullptr, frameId = %lu.", frameId);
            return ACL_ERROR_INTERNAL_ERROR;
        }
        if (callbackInfoPtr->outputPicDesc != nullptr) {
            callbackInfoPtr->outputPicDesc->dvppPicDesc = channelDesc->callbackResult.dvppPicDesc;
            output = callbackInfoPtr->outputPicDesc;
        }
        input = callbackInfoPtr->inputStreamDesc;
        userData = callbackInfoPtr->callbackData;
        eos = callbackInfoPtr->eos;
        if (eos) {
            if (channelDesc->callbackResult.errCode == DVPP_EOS_CHANNEL_ABNORMAL) {
                channelDesc->abnormalChannelEosFlag.store(true);
            }
        }

        ACL_LOG_INFO("vdec callback: channelId=%u, frameId = %lu, eos = %d",
            channelDesc->vdecDesc.channelId, frameId, static_cast<int32_t>(eos));

        return ACL_SUCCESS;
    }

    void VideoProcessor::GetVdecFrameCallback(void *const callbackData)
    {
        aclvdecChannelDesc *const channelDesc =  reinterpret_cast<aclvdecChannelDesc *>(callbackData);
        if ((channelDesc == nullptr) || (channelDesc->shareBuffer.data == nullptr)) {
            ACL_LOG_INNER_ERROR("[Check][Pointer]GetVdecFrameCallback callbackData = %p, "
                "but channelDesc or shareBuffer is null.", callbackData);
            return;
        }

        const uint32_t channelId = channelDesc->vdecDesc.channelId;
        // get vdec callback info
        acldvppStreamDesc *input = nullptr;
        acldvppPicDesc *output = nullptr;
        void *userData = nullptr;
        bool eos = false;
        const aclError aclRet = GetVdecCallInfo(channelDesc, input, output, userData, eos);
        if (aclRet != ACL_SUCCESS) {
            ACL_LOG_INNER_ERROR("[Get][VdecCallInfo]get vdec callback info failed, channelId = %u.", channelId);
            return;
        }

        if (eos) {
            const std::unique_lock<std::mutex> locker{channelDesc->mutexForQueue};
            ACL_LOG_INFO("Begin to process callback for eos, channelId = %u.", channelId);
            channelDesc->eosBackFlag.store(true);
            channelDesc->condVarForEos.notify_one();
            ACL_LOG_INFO("Finish to process callback for eos, channelId = %u.", channelId);
            return;
        }

        // launch task for get stream
        aicpu::dvpp::VdecCallbackInfoPtr nextCallbackInfo = nullptr;
        {
            const std::lock_guard<std::mutex> queueLock(channelDesc->mutexForQueue);
            ACL_LOG_INFO("task queue size is %zu, channelId = %u.", channelDesc->taskQueue.size(), channelId);
            if (channelDesc->taskQueue.empty()) {
                channelDesc->queueEmptyFlag.store(true);
            } else {
                nextCallbackInfo = channelDesc->taskQueue.front();
                channelDesc->taskQueue.pop();
            }
        }

        // launch task to get stream
        if (nextCallbackInfo != nullptr) {
            rtContext_t curContext = nullptr;
            // get current context
            const rtError_t getCtxRet = rtCtxGetCurrent(&curContext);
            if (getCtxRet != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Get][Context]get ctx failed, runtime errorCode = %d, "
                    "channelId = %u.", getCtxRet, channelId);
                return;
            }
            // set context of vdec main thread to current callback thread
            const rtError_t setCtxRet = rtCtxSetCurrent(channelDesc->vdecMainContext);
            if (setCtxRet != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Set][Context]set ctx failed, runtime errorCode = %d, "
                    "channelId = %u.", setCtxRet, channelId);
                return;
            }
            // launch task
            const aclError launchRet = LaunchTaskForGetStream(channelDesc);
            if (launchRet != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Get][Context]launch task for get stream failed.");
                (void) rtCtxSetCurrent(curContext);
                return;
            }
            // reset context of current callback thread
            const rtError_t resetCtxRet = rtCtxSetCurrent(curContext);
            if (resetCtxRet != RT_ERROR_NONE) {
                ACL_LOG_INNER_ERROR("[Set][Context]set ctx failed, runtime errorCode = %d, channelId = %u.",
                    resetCtxRet, channelId);
                return;
            }
        }

        // check user callback func
        if (channelDesc->callback == nullptr) {
            ACL_LOG_INNER_ERROR("[Check][Callback]call back func is null!");
            return;
        }
        // call user callback func
        (*channelDesc->callback)(input, output, userData);
    }

    aclError VideoProcessor::LaunchTaskForGetStream(aclvdecChannelDesc *const channelDesc)
    {
        static uint32_t launchTaskCount[VDEC_CHANNEL_ID_CEILING + 1] = {0U};
        if (channelDesc->isNeedNotify) {
            // launch get frame task to get frame stream
            const aclError getFrameRet = LaunchGetFrameTask(channelDesc, acl::dvpp::DVPP_KERNELNAME_GET_FRAME);
            if (getFrameRet != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Launch][Task]launch get frame task failed, errorCode = %d", getFrameRet);
                return getFrameRet;
            }

            // launch wait task to get frame stream
            const rtError_t getFrameWaitRet = rtNotifyWait(static_cast<rtNotify_t>(channelDesc->getFrameNotify),
                channelDesc->getFrameStream);
            if (getFrameWaitRet != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Wait][Notify]wait for a notify to get frame stream failed,\
                    runtime errorCode = %d", getFrameWaitRet);
                return ACL_GET_ERRCODE_RTS(getFrameWaitRet);
            }
        } else {
            // launch get frame task to get frame stream
            const aclError getFrameRet = LaunchGetFrameTask(channelDesc, acl::dvpp::DVPP_KERNELNAME_GET_FRAME_V2);
            if (getFrameRet != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Get][FrameTask]launch get frame task failed, errorCode = %d", getFrameRet);
                return getFrameRet;
            }
        }

        // launch callback task to get frame stream
        const rtError_t callbackRet = rtCallbackLaunch(&GetVdecFrameCallback,
                                                       static_cast<void *>(channelDesc),
                                                       channelDesc->getFrameStream, true);
        if (callbackRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Callback]launch callback to get frame stream failed, "
                "runtime errorCode = %d", callbackRet);
            return ACL_GET_ERRCODE_RTS(callbackRet);
        }

        const uint32_t channelId = channelDesc->vdecDesc.channelId;
        launchTaskCount[channelId]++;
        ACL_LOG_INFO("Launch task for get stream success. launchTaskCount = %u, channelId = %u, getStreamId = %u.",
            launchTaskCount[channelId], channelId, channelDesc->getStreamId);
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::LaunchTaskForSendStream(const aclvdecChannelDesc *const channelDesc,
                                                     acldvppStreamDesc *const input,
                                                     acldvppPicDesc *const output,
                                                     const bool eos) const
    {
        if (channelDesc->isNeedNotify) {
            // launch send frame task to send frame stream
            const aclError sendFrameRetVal = LaunchSendFrameTask(channelDesc, input, output, eos,
                acl::dvpp::DVPP_KERNELNAME_SEND_FRAME);
            if (sendFrameRetVal != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Launch][Task]launch send frame task failed, errorCode = %d", sendFrameRetVal);
                return sendFrameRetVal;
            }
            rtError_t sendFrameWaitRetVal;
            if (channelDesc->vdecWaitTaskType == NOTIFY_TASK) {
                // launch notify wait to send frame stream
                sendFrameWaitRetVal = rtNotifyWait(static_cast<rtNotify_t>(channelDesc->sendFrameNotify),
                    channelDesc->sendFrameStream);
                if (sendFrameWaitRetVal != RT_ERROR_NONE) {
                    ACL_LOG_CALL_ERROR("[Wait][Notify]wait for a notify to send frame stream failed, "
                        "runtime errorCode = %d", sendFrameWaitRetVal);
                    return ACL_GET_ERRCODE_RTS(sendFrameWaitRetVal);
                }
            } else {
                sendFrameWaitRetVal = rtStreamWaitEvent(channelDesc->sendFrameStream,
                    static_cast<rtEvent_t>(channelDesc->sendFrameNotify));
                if (sendFrameWaitRetVal != RT_ERROR_NONE) {
                    ACL_LOG_CALL_ERROR("[Wait][Event]wait for a event to send frame stream failed,\
                        runtime errorCode = %d", sendFrameWaitRetVal);
                    return ACL_GET_ERRCODE_RTS(sendFrameWaitRetVal);
                }
                sendFrameWaitRetVal = rtEventReset(static_cast<rtEvent_t>(channelDesc->sendFrameNotify),
                    channelDesc->sendFrameStream);
                if (sendFrameWaitRetVal != RT_ERROR_NONE) {
                    ACL_LOG_CALL_ERROR("[Reset][Event]reset a event to send frame stream failed,\
                        runtime errorCode = %d", sendFrameWaitRetVal);
                    return ACL_GET_ERRCODE_RTS(sendFrameWaitRetVal);
                }
            }
        } else {
            // launch send frame task to send frame stream
            const aclError sendFrameRetVal = LaunchSendFrameTask(channelDesc, input, output, eos,
                acl::dvpp::DVPP_KERNELNAME_SEND_FRAME_V2);
            if (sendFrameRetVal != ACL_SUCCESS) {
                ACL_LOG_INNER_ERROR("[Launch][Task]launch send frame task failed, errorCode = %d", sendFrameRetVal);
                return sendFrameRetVal;
            }
        }

        return ACL_SUCCESS;
    }

    void VideoProcessor::ClearCachedTasks(aclvdecChannelDesc *const channelDesc) const
    {
        // frameCounter reset to 0
        ACL_LOG_INFO("task queue size before clear is %zu.", channelDesc->taskQueue.size());
        while (!channelDesc->taskQueue.empty()) {
            channelDesc->taskQueue.pop();
        }
        // reset eos back flag to false
        channelDesc->eosBackFlag.store(false);
        channelDesc->queueEmptyFlag.store(true);
        {
            const std::unique_lock<std::mutex> locker{channelDesc->mutexForCallbackMap};
            channelDesc->callbackMap.clear();
        }
        channelDesc->frameId = 0U;
    }

    void VideoProcessor::DestroyAllNotifyForVdecChannel(aclvdecChannelDesc *const channelDesc) const
    {
        if (channelDesc->sendFrameNotify != nullptr) {
            const rtError_t rtRetVal = rtNotifyDestroy(static_cast<rtNotify_t>(channelDesc->sendFrameNotify));
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Notify]fail to destroy sendFrameNotify,\
                    runtime errorCode = %d", rtRetVal);
            }
            channelDesc->sendFrameNotify = nullptr;
        }

        if (channelDesc->getFrameNotify != nullptr) {
            const rtError_t rtRetVal = rtNotifyDestroy(static_cast<rtNotify_t>(channelDesc->getFrameNotify));
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Notify]fail to destroy getFrameNotify,\
                    runtime errorCode = %d", rtRetVal);
            }
            channelDesc->getFrameNotify = nullptr;
        }
    }

    void VideoProcessor::DestroyAllEventForVdecChannel(aclvdecChannelDesc *const channelDesc) const
    {
        if (channelDesc->sendFrameNotify != nullptr) {
            const rtError_t rtRetVal = rtEventDestroy(static_cast<rtEvent_t>(channelDesc->sendFrameNotify));
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Event]fail to destroy sendFrameNotify,\
                    runtime errorCode = %d", rtRetVal);
            }
            channelDesc->sendFrameNotify = nullptr;
        }

        if (channelDesc->getFrameNotify != nullptr) {
            const rtError_t rtRetVal = rtEventDestroy(static_cast<rtEvent_t>(channelDesc->getFrameNotify));
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Event]fail to destroy getFrameNotify, runtime errorCode = %d", rtRetVal);
            }
            channelDesc->getFrameNotify = nullptr;
        }
    }

    void VideoProcessor::DestroyAllNotifyAndStreamForVdecChannel(aclvdecChannelDesc *const channelDesc,
        const bool isNeedNotify) const
    {
        ACL_LOG_DEBUG("begin to destroy all notify and stream.");
        if (channelDesc == nullptr) {
            ACL_LOG_ERROR("[Check][ChannelDesc]vdec channel desc is null.");
            const char_t *argList[] = {"param"};
            const char_t *argVal[] = {"channelDesc"};
            acl::AclErrorLogManager::ReportInputErrorWithChar(acl::INVALID_NULL_POINTER_MSG,
                argList, argVal, 1U);
            return;
        }

        if (channelDesc->sendFrameStream != nullptr) {
            const rtError_t rtRetVal = rtStreamDestroy(channelDesc->sendFrameStream);
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Stream]fail to destroy sendFrameStream,\
                    runtime errorCode = %d", rtRetVal);
            }
            channelDesc->sendFrameStream = nullptr;
        }

        if (channelDesc->getFrameStream != nullptr) {
            const rtError_t rtRetVal = rtStreamDestroy(channelDesc->getFrameStream);
            if (rtRetVal != RT_ERROR_NONE) {
                ACL_LOG_CALL_ERROR("[Destroy][Stream]fail to destroy getFrameStream,\
                    runtime errorCode = %d", rtRetVal);
            }
            channelDesc->getFrameStream = nullptr;
        }

        if (isNeedNotify) {
            if (channelDesc->vdecWaitTaskType == NOTIFY_TASK) {
                DestroyAllNotifyForVdecChannel(channelDesc);
            } else {
                DestroyAllEventForVdecChannel(channelDesc);
            }
        }

        ACL_LOG_DEBUG("success to destroy all notify and stream.");
    }

    aclError VideoProcessor::CreateNotifyForVdecChannel(aclvdecChannelDesc *const channelDesc) const
    {
        int32_t deviceId = 0;
        rtError_t rtRet = rtGetDevice(&deviceId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][Device]fail to get deviceId when create vdec channel, "
                "runtime errorCode = %d", rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }

        // create notify for send frame
        rtNotify_t sendFrameNotify = nullptr;
        rtRet = rtNotifyCreate(deviceId, &sendFrameNotify);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Notify]fail to create sendFrameNotify, runtime errorCode = %d", rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->sendFrameNotify = static_cast<void *>(sendFrameNotify);

        // create notify for get frame
        rtNotify_t getFrameNotify = nullptr;
        rtRet = rtNotifyCreate(deviceId, &getFrameNotify);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Notify]fail to create getFrameNotify, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->getFrameNotify = static_cast<void *>(getFrameNotify);

        // get notifyId for send frame
        uint32_t sendFrameNotifyId = 0U;
        rtRet = rtGetNotifyID(sendFrameNotify, &sendFrameNotifyId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][NotifyID]fail to get sendFrameNotifyId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        ACL_LOG_INFO("sendFrameNotifyId is %u", sendFrameNotifyId);
        channelDesc->vdecDesc.sendFrameNotifyId = sendFrameNotifyId;

        // get notifyId for get frame
        uint32_t getFrameNotifyId = 0U;
        rtRet = rtGetNotifyID(getFrameNotify, &getFrameNotifyId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][NotifyID]fail to get getFrameNotifyId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        ACL_LOG_INFO("getFrameNotifyId is %u", getFrameNotifyId);
        channelDesc->vdecDesc.getFrameNotifyId = getFrameNotifyId;

        return ACL_SUCCESS;
    }

    aclError VideoProcessor::CreateEventForVdecChannel(aclvdecChannelDesc *const channelDesc) const
    {
        // create event for send frame
        rtEvent_t sendFrameEvent = nullptr;
        rtError_t rtRet = rtEventCreateWithFlag(&sendFrameEvent, RT_EVENT_WITH_FLAG);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Event]fail to create sendFrameEvent, runtime errorCode = %d", rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->sendFrameNotify = static_cast<void *>(sendFrameEvent);

        // create event for get frame
        rtEvent_t getFrameEvent = nullptr;
        rtRet = rtEventCreateWithFlag(&getFrameEvent, RT_EVENT_WITH_FLAG);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Event]fail to create getFrameEvent, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->getFrameNotify = static_cast<void *>(getFrameEvent);

        // get eventId for send frame
        uint32_t sendFrameEventId = 0U;
        rtRet = rtGetEventID(sendFrameEvent, &sendFrameEventId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][EventID]fail to get sendFrameEventId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        ACL_LOG_INFO("sendFrameEventId is %u", sendFrameEventId);
        channelDesc->vdecDesc.sendFrameNotifyId = sendFrameEventId;

        // get eventId for get frame
        uint32_t getFrameEventId = 0U;
        rtRet = rtGetEventID(getFrameEvent, &getFrameEventId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][EventID]fail to get getFrameEventId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, true);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        ACL_LOG_INFO("getFrameEventId is %u", getFrameEventId);
        channelDesc->vdecDesc.getFrameNotifyId = getFrameEventId;

        return ACL_SUCCESS;
    }

    aclError VideoProcessor::CreateNotifyAndStreamForVdecChannel(aclvdecChannelDesc *const channelDesc,
        const bool isNeedNotify)
    {
        if (isNeedNotify) {
            aclError aclRet;
            if (channelDesc->vdecWaitTaskType == NOTIFY_TASK) {
                aclRet = CreateNotifyForVdecChannel(channelDesc);
                if (aclRet != ACL_SUCCESS) {
                    return aclRet;
                }
            } else {
                aclRet = CreateEventForVdecChannel(channelDesc);
                if (aclRet != ACL_SUCCESS) {
                    return aclRet;
                }
            }
        }

        // create stream for send frame
        rtStream_t sendFrameStream = nullptr;
        rtError_t rtRet = rtStreamCreate(&sendFrameStream, static_cast<int32_t>(RT_STREAM_PRIORITY_DEFAULT));
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Stream]fail to create sendFrameStream, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->sendFrameStream = sendFrameStream;

        // create stream for get frame
        rtStream_t getFrameStream = nullptr;
        rtRet = rtStreamCreate(&getFrameStream, static_cast<int32_t>(RT_STREAM_PRIORITY_DEFAULT));
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Create][Stream]fail to create getFrameStream, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->getFrameStream = getFrameStream;

        // get streamId for get frame
        int32_t sendStreamId = 0;
        rtRet = rtGetStreamId(sendFrameStream, &sendStreamId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][StreamId]fail to get sendStreamId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->sendStreamId = sendStreamId;

        // get streamId for send frame
        int32_t getStreamId = 0;
        rtRet = rtGetStreamId(getFrameStream, &getStreamId);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Get][StreamId]fail to get getStreamId, runtime errorCode = %d", rtRet);
            DestroyAllNotifyAndStreamForVdecChannel(channelDesc, isNeedNotify);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        channelDesc->getStreamId = getStreamId;

        return ACL_SUCCESS;
    }

    aclError VideoProcessor::LaunchSendFrameTask(const aclvdecChannelDesc *const channelDesc,
                                                 acldvppStreamDesc *const inputStreamDesc,
                                                 acldvppPicDesc *const outputPicDesc,
                                                 const bool eos,
                                                 const char_t *const kernelName) const
    {
        // send frame task has 3 input
        constexpr uint32_t ioAddrNum = 3U;
        constexpr uint32_t argsSize = static_cast<uint32_t>(sizeof(aicpu::AicpuParamHead) +
            (ioAddrNum * sizeof(uint64_t)) + sizeof(uint64_t));
        const std::unique_ptr<char_t[]> args(new (std::nothrow)char_t[argsSize]);
        ACL_REQUIRES_NOT_NULL(args);
        const auto paramHead = reinterpret_cast<aicpu::AicpuParamHead *>(args.get());
        paramHead->length = argsSize;
        paramHead->ioAddrNum = ioAddrNum;
        const auto ioAddr = reinterpret_cast<uint64_t *>(args.get() + sizeof(aicpu::AicpuParamHead));
        int32_t i = 0;
        ioAddr[i] = reinterpret_cast<uintptr_t>(channelDesc->dataBuffer.data);
        ++i;
        ioAddr[i] = reinterpret_cast<uintptr_t>(inputStreamDesc->dataBuffer.data);
        ++i;
        if ((!eos) && (outputPicDesc != nullptr)) {
            ioAddr[i] = reinterpret_cast<uintptr_t>(outputPicDesc->dataBuffer.data);
        } else {
            ioAddr[i] = reinterpret_cast<uintptr_t>(nullptr);
        }
        const auto frameId = reinterpret_cast<uint64_t *>(args.get() + sizeof(aicpu::AicpuParamHead)
            + (ioAddrNum * sizeof(uint64_t)));
        if (!eos) {
            *frameId = channelDesc->frameId;
        } else {
            *frameId = 0U; // 0 represents eos frame id
            ACL_LOG_INFO("vdec process eos frame: channelId = %u, frameId = %lu",
                channelDesc->vdecDesc.channelId, *frameId);
        }
        rtArgsEx_t argsInfo = {};
        argsInfo.args = args.get();
        argsInfo.argsSize = argsSize;
        const rtError_t rtRet = rtCpuKernelLaunchWithFlag(acl::dvpp::DVPP_KERNELS_SONAME,
                                                          kernelName,
                                                          1U, // blockDim default 1
                                                          &argsInfo,
                                                          nullptr, // no need smDesc
                                                          channelDesc->sendFrameStream,
                                                          RT_KERNEL_DEFAULT);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Task]vdec send frame task call rtCpuKernelLaunchWithFlag failed, "
                "runtime errorCode = %d.", rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        return ACL_SUCCESS;
    }

    aclError VideoProcessor::LaunchGetFrameTask(const aclvdecChannelDesc *const channelDesc,
        const char_t *const kernelName)
    {
        // get frame task has 1 input
        constexpr uint32_t ioAddrNum = 1U;
        constexpr uint32_t argsSize = static_cast<uint32_t>(sizeof(aicpu::AicpuParamHead) +
            (ioAddrNum * sizeof(uint64_t)));
        const std::unique_ptr<char_t[]> args(new (std::nothrow)char_t[argsSize]);
        ACL_REQUIRES_NOT_NULL(args);
        const auto paramHead = reinterpret_cast<aicpu::AicpuParamHead *>(args.get());
        paramHead->length = argsSize;
        paramHead->ioAddrNum = ioAddrNum;
        const auto ioAddr = reinterpret_cast<uint64_t *>(args.get() + sizeof(aicpu::AicpuParamHead));
        ioAddr[0] = reinterpret_cast<uintptr_t>(channelDesc->dataBuffer.data);
        rtArgsEx_t argsInfo = {};
        argsInfo.args = args.get();
        argsInfo.argsSize = argsSize;
        const rtError_t rtRet = rtCpuKernelLaunchWithFlag(acl::dvpp::DVPP_KERNELS_SONAME,
                                                          kernelName,
                                                          1U, // blockDim default 1
                                                          &argsInfo,
                                                          nullptr, // no need smDesc
                                                          channelDesc->getFrameStream,
                                                          RT_KERNEL_DEFAULT);
        if (rtRet != RT_ERROR_NONE) {
            ACL_LOG_CALL_ERROR("[Launch][Task]vdec get frame task call rtCpuKernelLaunchWithFlag failed, "
                "runtime errorCode = %d.", rtRet);
            return ACL_GET_ERRCODE_RTS(rtRet);
        }
        return ACL_SUCCESS;
    }

    /**
     * VDEC set outout pic Wdith for channel desc.
     * @param channelDesc[in|out] channel desc
     * @param outPicWidth[in] outPicWidth
     * @return ACL_SUCCESS for ok, others for fail
     */
    aclError VideoProcessor::aclvdecSetChannelDescOutPicWidth(aclvdecChannelDesc *const channelDesc,
                                                              const uint32_t outPicWidth) const
    {
        ACL_LOG_DEBUG("start to execute aclvdecSetChannelDescOutPicWidth");
        ACL_REQUIRES_NOT_NULL(channelDesc);

        channelDesc->vdecDesc.outPicWidth = outPicWidth;
        return ACL_SUCCESS;
    }

    /**
     * VDEC set outout pic Height for channel desc.
     * @param channelDesc[in|out] channel desc
     * @param outHeight[in] outHeight
     * @return ACL_SUCCESS for ok, others for fail
     */
    aclError VideoProcessor::aclvdecSetChannelDescOutPicHeight(aclvdecChannelDesc *const channelDesc,
                                                               const uint32_t outPicHeight) const
    {
        ACL_LOG_DEBUG("start to execute aclvdecSetChannelDescOutPicHeight");
        ACL_REQUIRES_NOT_NULL(channelDesc);

        channelDesc->vdecDesc.outPicHeight = outPicHeight;
        return ACL_SUCCESS;
    }

    /**
     * VDEC set refFrameNum for channel desc.
     * @param channelDesc[in|out] channel desc
     * @param refFrameNum[in] refFrameNum
     * @return ACL_SUCCESS for ok, others for fail
     */
    aclError VideoProcessor::aclvdecSetChannelDescRefFrameNum(aclvdecChannelDesc *const channelDesc,
                                                              const uint32_t refFrameNum) const
    {
        (void)(channelDesc);
        (void)(refFrameNum);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Setting refFrameNum for channel desc is not "
            "supported in this version. Please check.");
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    /**
     * VDEC get refFrameNum for channel desc.
     * @param channelDesc[in] channel desc
     * @retval number of reference frames, default 0.
     */
    uint32_t VideoProcessor::aclvdecGetChannelDescRefFrameNum(const aclvdecChannelDesc *const channelDesc) const
    {
        (void)(channelDesc);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Getting refFrameNum for channel desc is not "
            "supported in this version. Please check.");
        return 0U;
    }

    /**
      * VDEC set outPicFormat for channel desc.
      * @param channelDesc[in|out] channel desc
      * @param outPicFormat[in] outPicFormat
      * @return ACL_SUCCESS for ok, others for fail
      */
    aclError VideoProcessor::aclvdecSetChannelDescOutPicFormat(aclvdecChannelDesc *const channelDesc,
                                                               const acldvppPixelFormat outPicFormat) const
    {
        (void)(channelDesc);
        (void)(outPicFormat);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Setting outPicFormat for channel desc is not "
            "supported in this version. Please check.");
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    /**
     * VDEC set channel id for channel desc.
     * @param channelDesc[in|out] channel desc
     * @param channelId[in] channel id
     * @return ACL_SUCCESS for ok, others for fail
     */
    aclError VideoProcessor::aclvdecSetChannelDescChannelId(aclvdecChannelDesc *const channelDesc,
                                                            const uint32_t channelId) const
    {
        (void)(channelDesc);
        (void)(channelId);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Setting channelId for channel desc is not "
            "supported in this version. Please check.");
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    /**
     * VDEC set bit depth for channel desc.
     * @param channelDesc [IN]     vdec channel description.
     * @param bitDepth [IN]     bit depth.
     * @return ACL_SUCCESS for ok, others for fail
     */
    aclError VideoProcessor::aclvdecSetChannelDescBitDepth(aclvdecChannelDesc *const channelDesc,
        const uint32_t bitDepth) const
    {
        (void)(channelDesc);
        (void)(bitDepth);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Setting bit depth for vedc channel desc is "
            "not supported in this version. Please check.");
        return ACL_ERROR_FEATURE_UNSUPPORTED;
    }

    /**
     * VDEC get bit depth for channel desc.
     * @param channelDesc [IN]    vdec channel description.
     * @retval bit depth, default 0.
     */
    uint32_t VideoProcessor::aclvdecGetChannelDescBitDepth(const aclvdecChannelDesc *const channelDesc) const
    {
        (void)(channelDesc);
        ACL_LOG_INNER_ERROR("[Unsupport][Feature]Getting bit depth for vedc channel desc is "
            "not supported in this version. Please check.");
        return 0U;
    }
    }
}
